/*******************************************************************************

                     LVGL输入法之内码输入法实现
本输入法负责管理输入法软键盘，及其响应，为完整输入法，且仅支持触模不支持实体按键
输入法为十六进制，需输入4位，键盘首行显示如: @GB2312 | B3C_ | Unicode
内码字符查询：http://www.mytju.com/classCode/tools/encode_gb2312.asp
*******************************************************************************/
#include "lvIME_Base.h"
#include "GB2312_UCS2.h"
#include "Unicode_Utf8.h"
#include <string.h>

//----------------------------7x4模式键盘布局定义--------------------------------
//内码模式为专用，不能通过切换功能键切入或切出，故取消切换键
//仅支持GB2312模式与UNICODE-BMP模式
static const char * BTNMAP_CONST _KbBtnMap[] = {
 LV_SYMBOL_KEYBOARD, lvIME_SignBuf[0], lvIME_SignBuf[1], lvIME_SignBuf[2], LV_SYMBOL_BACKSPACE,"\n",
 LV_SYMBOL_LEFT,"0", "1", "2","3", "4", LV_SYMBOL_RIGHT,"\n",
   "_",    "5", "6","7", "8", "9",  LV_SYMBOL_CLOSE, "\n",
      "A", "B", "C", "D", "E", "F", LV_SYMBOL_OK, ""};

//位置转键值,与_KbBtnMapH对应
static const signed char _KbPos2Key[] = {
  LV_KEY_HOME, 'a',     'b',      'c', LV_KEY_BACKSPACE,
  LV_KEY_LEFT, '0',  '1', '2', '3', '4', LV_KEY_RIGHT,
  ' ',         '5',  '6', '7', '8', '9', LV_KEY_ESC,
         'A',  'B',  'C', 'D',  'E',  'F',  LV_KEY_ENTER};

//直接内部静态实现，以在重入时自动恢复:
static unsigned char _IsUnicode = 0;    //是否为Unicode按键，否则为GB2312
static unsigned char _InPos = 0;        //用户输入的代码
static unsigned char _Code[4];         //用户输入的代码

//内部字符，限制为6个字节
static const char _GB2312[] = "GB2312";
static const char _Unicode[] = "Unicode";

//----------------------更新动态按键的显示---------------------------------
//返回创建的对像
static void _UpdateDisp(lv_obj_t *pBtnM)
{
  //GB2312按钮指示
  char *pSignBuf = lvIME_SignBuf[0];
  if(_IsUnicode) pSignBuf[0] = ' ';
  else pSignBuf[0] = '@';
  strcpy(&pSignBuf[1], _GB2312);
  //用户输入提示
  pSignBuf += LV_IME_SIGN_BYTE;
  for(unsigned char i = 0; i < _InPos; i++) pSignBuf[i] = _Code[i];
  memset(&pSignBuf[_InPos], '_', 4 - _InPos);
  pSignBuf[4]  = '\0';//固定结束位置
  //Unicode按钮指示
  pSignBuf += LV_IME_SIGN_BYTE;
  if(_IsUnicode) pSignBuf[0] = '@';
  else pSignBuf[0] = ' ';
  strcpy(&pSignBuf[1], _Unicode);

  //重新设置并更新
  lv_buttonmatrix_set_map(pBtnM, (const char **)_KbBtnMap);
}

//-------------------------创建内码输入法----------------------------------
//返回创建的对像
lv_obj_t *lvIME_CreateInCode(lv_event_cb_t _cbEventHandler, //回调函数
                             void *pv)//回调函数带的参数
{
  lv_obj_t * pBtnM = lvIME_CreateKeyStart(_cbEventHandler, pv);
  //横向铺满键盘
  lv_obj_set_size(pBtnM, lv_pct(100), LV_IME_KB_ROW_HIGHT * 4);
  _UpdateDisp(pBtnM);//更新键盘区
  lv_obj_update_layout(pBtnM); //强制更新布局以使大小生效
  return pBtnM;
}

//---------------------------------字符转十六进制---------------------------
static unsigned char _Letter2Hex(char Letter)
{
  if((Letter >= 'A') && (Letter <= 'F')) return Letter - ('A' - 10);
  if((Letter >= '0') && (Letter <= '9')) return Letter - '0';
  return 0;
}

//------------------------------输入十六进制后的处理函数---------------------
//返回0内部已处理:
//返回-1,字符完成，UTF8放在了lvIME_SignBuf[3]里
static signed char _AddHex(lv_obj_t *pBtnM, signed char Key)
{
  //Uncode全码支持
  if(_IsUnicode){
    _Code[_InPos++] = Key;
  }
  else{//检查GB2312合法性，正确才可输入，检查范围：A1A1至F7FE
    if(_InPos == 0){
      if(Key < 'A') return 0;
    }
    else if(_InPos == 1){
      if((_Code[0] <= 'A') && (Key < '1')) return 0;
      else if((_Code[0] >= 'F') && (Key > '7')) return 0;
    }
    else if(_InPos == 2){
      if(Key < 'A') return 0;
    }
    else if(_InPos == 3){
      if((_Code[2] <= 'A') && (Key < '1')) return 0;
      else if((_Code[2] >= 'F') && (Key > 'E')) return 0;
    }
    _Code[_InPos++] = Key;
  }
  if(_InPos < 4){ //未输入完成
    _UpdateDisp(pBtnM);
    return 0;
  }
  //输入完成了,转换到缓冲区输出
  unsigned short Code = _Letter2Hex(_Code[0]); Code <<= 12;
  Code += (unsigned short)_Letter2Hex(_Code[1]) << 8;
  Code += (unsigned short)_Letter2Hex(_Code[2]) << 4;
  Code += (unsigned short)_Letter2Hex(_Code[3]) << 0;
  if(!_IsUnicode) Code = GB2312ToUcs2(Code); //GB2312转Unicode
  //Unicode转UTF8
  lvIME_SignBuf[4][Code_UcsToUtf8(&Code, 1,lvIME_SignBuf[4],
                                  LV_IME_SIGN_BYTE)] = '\0';
  _InPos = 0;//复位了
  _UpdateDisp(pBtnM);
  return -1;   //输入完成
}

//-------------------------获得输入法按键后的键值---------------------------
//返回0内部已处理;
//返回-1,字符完成，需立即lvIME_GetInCodeChar()读取字符
//返回其它：需进行处理
signed char lvIME_GetInCodeKey(lv_obj_t *pBtnM) //lv_buttonmatrix对像
{
  signed char Key = _KbPos2Key[lv_btnmatrix_get_selected_btn(pBtnM)];
  //输入法切换
  if((Key >= 'a') && (Key <= 'c')){
    if(Key == 'a'){//切2312
      if(!_IsUnicode) return 0;
       _IsUnicode = 0;
       _InPos = 0;//有合法性，需重新输入
    }
    else if(Key == 'c'){//切unicode
      if(_IsUnicode) return 0;
      _IsUnicode = 1;
    }
    else{// if(Key == 'b')内部后撤处理
      if(_InPos) _InPos--;
    }
    _UpdateDisp(pBtnM);
    return 0;
  }
  if(Key == LV_KEY_BACKSPACE){
    if(_InPos){ //本地后撤
      _InPos--;
      _UpdateDisp(pBtnM);
      return 0;
    }
    else return Key; //用户后撤
  }
  if((Key >= '0') && (Key <= '9'))  return _AddHex(pBtnM, Key);
  if((Key >= 'A') && (Key <= 'F')) return _AddHex(pBtnM, Key);
  return Key;
}

//-----------------------读取输入的字符---------------------------
//lvIME_GetInCodeKey()返回-1时调用
const char *lvIME_GetInCodeChar(lv_obj_t *pBtnM) //lv_buttonmatrix对像
{
  return lvIME_SignBuf[4];
}
